<template>
	<div :class="wrapClasses">
		<div v-if="type=='textarea'">
			<textarea
				:id="id"
				:wrap="wrap"
				:autocomplete="autocomplete"
				:spellcheck="spellcheck"
				ref="textarea"
				:class="textareaClasses"
				:style="textareaStyles"
				:placeholder="placeholder"
				:disabled="itemDisabled"
				:rows="rows"
				:maxlength="maxlength"
				:readonly="readonly"
				:name="name"
				:value="currentValue"
				:autofocus="autofocus"
				@keyup.enter="handleEnter"
				@keyup="handleKeyup"
				@keypress="handleKeypress"
				@keydown="handleKeydown"
				@focus="handleFocus"
				@blur="handleBlur"
				@compositionstart="handleComposition"
				@compositionupdate="handleComposition"
				@compositionend="handleComposition"
				@input="handleInput"
			></textarea>
			<span class="ivu-input-word-count" v-if="showWordLimit">{{ textLength }}/{{ upperLimit }}</span>
		</div>
		<div v-else>
			<div :class="[prefixCls + '-group-prepend']" v-if="prepend" v-show="slotReady">
				<slot name="prepend"></slot>
			</div>
			<i
				class="ivu-icon"
				:class="['ivu-icon-ios-close-circle', prefixCls + '-icon', prefixCls + '-icon-clear' , prefixCls + '-icon-normal']"
				v-if="clearable && currentValue && !itemDisabled"
				@click="handleClear"
			></i>
			<i
				class="ivu-icon"
				:class="['ivu-icon-' + icon, prefixCls + '-icon', prefixCls + '-icon-normal']"
				v-else-if="icon"
				@click="handleIconClick"
			></i>
			<i
				class="ivu-icon ivu-icon-ios-search"
				:class="[prefixCls + '-icon', prefixCls + '-icon-normal', prefixCls + '-search-icon']"
				v-else-if="search && enterButton === false"
				@click="handleSearch"
			></i>
			<span class="ivu-input-suffix" v-else-if="showSuffix">
				<slot name="suffix">
					<i class="ivu-icon" :class="['ivu-icon-' + suffix]" v-if="suffix"></i>
				</slot>
			</span>
			<span class="ivu-input-word-count" v-else-if="showWordLimit">{{ textLength }}/{{ upperLimit }}</span>
			<span class="ivu-input-suffix pass" v-else-if="password" @click="handleToggleShowPassword">
				<i class="ivu-icon ivu-icon-ios-eye-off-outline" v-if="showPassword"></i>
				<i class="ivu-icon ivu-icon-ios-eye-outline" v-else></i>
			</span>
			<transition name="fade">
				<i
					class="ivu-icon ivu-icon-ios-loading ivu-load-loop"
					:class="[prefixCls + '-icon', prefixCls + '-icon-validate']"
					v-if="!icon"
				></i>
			</transition>
			<input
				:id="id"
				:autocomplete="autocomplete"
				:spellcheck="spellcheck"
				ref="input"
				:type="currentType"
				:class="inputClasses"
				:placeholder="placeholder"
				:disabled="itemDisabled"
				:maxlength="maxlength"
				:readonly="readonly"
				:name="name"
				:value="currentValue"
				:number="number"
				:autofocus="autofocus"
				@keyup.enter="handleEnter"
				@keyup="handleKeyup"
				@keypress="handleKeypress"
				@keydown="handleKeydown"
				@focus="handleFocus"
				@blur="handleBlur"
				@compositionstart="handleComposition"
				@compositionupdate="handleComposition"
				@compositionend="handleComposition"
				@input="handleInput"
				@change="handleChange"
			/>
			<div :class="[prefixCls + '-group-append']" v-if="append" v-show="slotReady">
				<slot name="append"></slot>
			</div>
			<div
				:class="[prefixCls + '-group-append', prefixCls + '-search']"
				v-else-if="search && enterButton"
				@click="handleSearch"
			>
				<i class="ivu-icon ivu-icon-ios-search" v-if="enterButton === true"></i>
				<template v-else>{{ enterButton }}</template>
			</div>
			<span class="ivu-input-prefix" v-else-if="showPrefix">
				<slot name="prefix">
					<i class="ivu-icon" :class="['ivu-icon-' + prefix]" v-if="prefix"></i>
				</slot>
			</span>
		</div>
	</div>
</template>

<script lang="ts">
	import { Vue, Prop, Emit, Component, Watch } from "vue-property-decorator";
	import { oneOf } from "../../utils/assist";
	import calcTextareaHeight from "../../utils/calcTextareaHeight";
	const prefixCls = "ivu-input";

	@Component
	export default class Input extends Vue {
		@Prop({
			type: [String, Number],
			default: ""
		})
		value!: string | number;

		@Prop({
			type: String,
			default: "text",
			validator: (val: string) => {
				return oneOf(val, [
					"text",
					"textarea",
					"password",
					"url",
					"email",
					"date",
					"number",
					"tel"
				]);
			}
		})
		type!: string;

		@Prop({
			validator(value) {
				return oneOf(value, ["small", "large", "default"]);
			},
			default() {
				return "default";
				/* 	return !this.$IVIEW || this.$IVIEW.size === ""
																											? "default"
																											: this.$IVIEW.size; */
			}
		})
		size!: string;

		@Prop({
			type: String,
			default: "soft",
			validator(value) {
				return oneOf(value, ["hard", "soft"]);
			}
		})
		wrap!: string;
		@Prop() id!: string;
		@Prop() name!: string;
		@Prop() icon!: string;
		@Prop({ default: "" }) prefix!: string;
		@Prop({ default: "" }) suffix!: string;
		@Prop() placeholder!: string;
		@Prop({ type: Boolean, default: false }) autocomplete!: boolean;
		@Prop({ type: Boolean, default: false }) autofocus!: boolean;
		@Prop({ type: Boolean, default: false }) spellcheck!: boolean;
		@Prop({ type: Boolean, default: false }) search!: boolean;
		@Prop({ type: Boolean, default: false }) enterButton!: boolean;
		@Prop({ type: Boolean, default: false }) readonly!: boolean;
		@Prop({ type: Boolean, default: false }) itemDisabled!: boolean;
		@Prop({ type: Boolean, default: false }) showWordLimit!: boolean;
		@Prop({ type: Boolean, default: false }) password!: boolean;
		@Prop({ type: Boolean, default: false }) clearable!: boolean;
		@Prop({ type: Boolean, default: false }) maxlength!: number;
		@Prop({ type: Boolean, default: false }) disabled!: boolean;
		@Prop({ type: Boolean, default: false }) autosize!: boolean;
		@Prop({ type: Boolean, default: false }) number!: boolean;
		@Prop({ type: Number, default: 2 }) rows!: number;
		@Prop({ type: Number, default: 2 }) minRows!: number;
		@Prop({ type: Number, default: 20 }) maxRows!: number;

		currentValue = this.value;
		prefixCls = prefixCls;
		slotReady = false;
		textareaStyles = {};
		isOnComposition = false;
		showPassword = false;

		get wrapClasses() {
			return [
				`${prefixCls}-wrapper`,
				{
					[`${prefixCls}-wrapper-${this.size}`]: !!this.size,
					[`${prefixCls}-type-${this.type}`]: this.type,
					[`${prefixCls}-group`]:
						this.prepend || this.append || (this.search && this.enterButton),
					[`${prefixCls}-group-${this.size}`]:
						(this.prepend || this.append || (this.search && this.enterButton)) &&
						!!this.size,
					[`${prefixCls}-group-with-prepend`]: this.prepend,
					[`${prefixCls}-group-with-append`]:
						this.append || (this.search && this.enterButton),
					[`${prefixCls}-hide-icon`]: this.append, // #554
					[`${prefixCls}-with-search`]: this.search && this.enterButton
				}
			];
		}

		get inputClasses() {
			return [
				`${prefixCls}`,
				{
					[`${prefixCls}-${this.size}`]: !!this.size,
					[`${prefixCls}-disabled`]: this.itemDisabled,
					[`${prefixCls}-with-prefix`]: this.showPrefix,
					[`${prefixCls}-with-suffix`]:
						this.showSuffix || (this.search && this.enterButton === false)
				}
			];
		}
		get textareaClasses() {
			return [
				`${prefixCls}`,
				{
					[`${prefixCls}-disabled`]: this.itemDisabled
				}
			];
		}

		get currentType() {
			let type = this.type;
			if (type === "password" && this.password && this.showPassword)
				type = "text";
			return type;
		}
		get prepend() {
			let state = false;
			if (this.type !== "textarea") state = this.$slots.prepend !== undefined;
			return state;
		}
		get append() {
			let state = false;
			if (this.type !== "textarea") state = this.$slots.append !== undefined;
			return state;
		}
		get showPrefix() {
			let state = false;
			if (this.type !== "textarea")
				state = this.prefix !== "" || this.$slots.prefix !== undefined;
			return state;
		}
		get showSuffix() {
			let state = false;
			if (this.type !== "textarea")
				state = this.suffix !== "" || this.$slots.suffix !== undefined;
			return state;
		}
		get upperLimit() {
			return this.maxlength;
		}
		get textLength() {
			if (typeof this.value === "number") {
				return String(this.value).length;
			}

			return (this.value || "").length;
		}

		setCurrentValue(value: string) {
			if (value === this.currentValue) return;
			this.$nextTick(() => {
				this.resizeTextarea();
			});
			this.currentValue = value;
			/* 	if (
																						!findComponentUpward(null, this, [
																							"DatePicker",
																							"TimePicker",
																							"Cascader",
																							"Search"
																						])
																					) {
																						this.$store.dispatch("FormItem", "on-form-change", value);
																					} */
		}

		@Watch("value")
		onChangeValue(newVal: string, oldVal: string) {		
			this.setCurrentValue(newVal);
		}
		@Emit()
		handleEnter(event: Event) {
			this.$emit("on-enter", event);
			if (this.search) this.$emit("on-search", this.currentValue);
		}
		@Emit()
		handleKeydown(event: Event) {
			this.$emit("on-keydown", event);
		}
		@Emit()
		handleKeypress(event: Event) {
			this.$emit("on-keypress", event);
		}
		@Emit()
		handleKeyup(event: Event) {
			this.$emit("on-keyup", event);
		}
		@Emit()
		handleIconClick(event: Event) {
			this.$emit("on-click", event);
		}
		@Emit()
		handleFocus(event: Event) {
			this.$emit("on-focus", event);
		}
		@Emit()
		handleBlur(event: Event) {
			this.$emit("on-blur", event);
			/* 	if (
																							!findComponentUpward( this, [
																								"DatePicker",
																								"TimePicker",
																								"Cascader",
																								"Search"
																							])
																						) {
																						this.dispatch("FormItem", "on-form-blur", this.currentValue);
																						} */
		}
		@Emit()
		handleComposition(event: Event) {
			if (event.type === "compositionstart") {
				this.isOnComposition = true;
			}
			if (event.type === "compositionend") {
				this.isOnComposition = false;
				this.handleInput(event);
			}
		}
		@Emit()
		handleInput(event: Event) {
			if (this.isOnComposition) return;
			let value = "";
			if (this.type === "textarea") {
				value = (this.$refs.textarea as HTMLTextAreaElement).value;
			} else {
				value = (this.$refs.input as HTMLInputElement).value;
			}
			if (this.number && value !== "") {
				const numValue = Number.isNaN(Number(value))
					? value ?? ""
					: Number(value);
				value = numValue.toString();
			}

			this.$emit("input", value);
			this.setCurrentValue(value ?? "");
			this.$emit("on-change", event);
		}
		@Emit()
		handleChange(event: Event) {
			this.$emit("on-input-change", event);
		}

		resizeTextarea() {
			const autosize = this.autosize;
			if (!autosize || this.type !== "textarea") {
				return false;
			}

			const minRows = this.minRows;
			const maxRows = this.maxRows;

			this.textareaStyles = calcTextareaHeight(
				this.$refs.textarea as HTMLTextAreaElement,
				minRows,
				maxRows
			);
		}
		focus() {
			if (this.type === "textarea") {
				(this.$refs.textarea as HTMLElement).focus();
			} else {
				(this.$refs.input as HTMLElement).focus();
			}
		}
		blur() {
			if (this.type === "textarea") {
				(this.$refs.textarea as HTMLElement).blur();
			} else {
				(this.$refs.input as HTMLElement).blur();
			}
		}
		handleClear() {
			const e = { target: { value: "" } };
			this.$emit("input", "");
			this.setCurrentValue("");
			this.$emit("on-change", e);
			this.$emit("on-clear");
		}
		handleSearch() {
			if (this.itemDisabled) return false;
			(this.$refs.input as HTMLElement).focus();
			this.$emit("on-search", this.currentValue);
		}
		handleToggleShowPassword() {
			if (this.itemDisabled) return false;
			this.showPassword = !this.showPassword;
			this.focus();
			const len = this.currentValue.toString().length;
			setTimeout(() => {
				(this.$refs.input as HTMLInputElement).setSelectionRange(len, len);
			}, 0);
		}
	}
</script>

<style>
</style>